`timescale 1ns / 1ps

// N in --> 1 out
module reduceWidth
#(
    parameter N     = 3,
    parameter WIDTH = 8
)
(
    input   clk,
    input   rst,
    
    input   i_vld,
    output  i_rdy,
    input   [N*WIDTH-1 : 0] i_data,
    
    output  o_vld,
    input   o_rdy,
    output  [WIDTH-1: 0]    o_data
);

localparam S0_IDLE   = 2'b01;
localparam S1_RUN    = 2'b10;

// real reg
reg [1: 0] cstate;

// combinatorial logic
reg [1: 0] nstate;
reg reg_en;
reg reg_ls;
reg ii_rdy;
reg oo_vld;
reg cnt_en;
wire cnt_last;

assign i_rdy = ii_rdy;
assign o_vld = oo_vld;

PISO_SReg #(
    .N      (N),
    .WIDTH  (WIDTH)
) inst_sreg
(
    .clk    (clk),
    .clken  (reg_en),
    .ld_sh  (reg_ls),
    .i_data (i_data),
    .o_data (o_data)
);

zq_counter #(
    .N  (N)
) inst_cnt
(
    .clk    (clk),
    .rst    (rst),
    .clken  (cnt_en),
    .last   (cnt_last),
    .out    ()
);

always @ (posedge clk)
begin
    if (rst)
        cstate <= S0_IDLE;
    else
        cstate <= nstate;
end

always @ (*)
begin
    case(cstate)
		S0_IDLE: begin
            nstate = i_vld ? S1_RUN : S0_IDLE;
		end
		S1_RUN: begin
            if (o_rdy & ~i_vld & cnt_last) begin
                nstate = S0_IDLE;
            end
            else begin
                nstate = S1_RUN;
            end
		end
		default: begin
			nstate = S0_IDLE;
		end
	endcase
end

always @ (*)
begin
    case(cstate)
		S0_IDLE: begin
            reg_en = i_vld;
            reg_ls = 1'b0;
            cnt_en = 1'b0;
            ii_rdy = 1'b1;
            oo_vld = 1'b0;
		end
		S1_RUN: begin
            if (cnt_last) begin
                reg_en = o_rdy & i_vld;
                reg_ls = 1'b0;
                cnt_en = o_rdy;
                ii_rdy = o_rdy;
            end
            else begin
                reg_en = o_rdy;
                reg_ls = 1'b1;
                cnt_en = o_rdy;
                ii_rdy = 1'b0;
            end
		    oo_vld = 1'b1;
		end
		default: begin
            reg_en = 1'b0;
            reg_ls = 1'b0;
            ii_rdy = 1'b0;
            oo_vld = 1'b0;
            cnt_en = 1'b0;
		end
	endcase
end

endmodule
